package main

import (
	"log"
	"runtime"
	"time"
)

func init() {
	log.SetPrefix("TRACE: ")
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
}
func main() {
	//没有缓存的通道具有同步功能
	c := make(chan struct{})
	ci := make(chan int, 100)
	go func(i chan struct{}, j chan int) {
		for i := 0; i < 10; i++ {
			ci <- i
		}
		//不关闭的话，range 读取会发送死锁|are asleep - deadlock!
		close(ci)
		log.Println("写通道")
		c <- struct{}{}
	}(c, ci)

	// 返回当前程序的goroutine数目
	log.Println("NumGoroutine=", runtime.NumGoroutine())
	//读通道 c,通过通道进行同步等待
	<-c
	//此时ci 通道已经关闭，匿名函数 goroutine退出
	log.Println("NumGoroutine=", runtime.NumGoroutine())
	//但 通道ci 还可以继续读取
	go func() {
		for v := range ci {
			log.Println(v)
		}
		c <- struct{}{}
		//这样不能读到全部数据
		/*for {
			if num, ok := <-ci; ok == true { //ok=true表示通道未关闭
				fmt.Println("读到数据：", num)
			} else {
				fmt.Println("通道已关闭，没有数据了")
				break
			}
			c <- struct{}{}
		}*/
	}()
	<-c
}

func chanDemo2() {
	c := make(chan struct{})
	ci := make(chan int, 100)
	go func(i chan struct{}, j chan int) {
		for i := 0; i < 10; i++ {
			ci <- i
		}
		//不关闭的话，range 读取会发送死锁|are asleep - deadlock!
		close(ci)
		log.Println("写通道")
		c <- struct{}{}
	}(c, ci)

	// 返回当前程序的goroutine数目
	log.Println("NumGoroutine=", runtime.NumGoroutine())
	//读通道 c,通过通道进行同步等待
	<-c
	//此时ci 通道已经关闭，匿名函数 goroutine退出
	log.Println("NumGoroutine=", runtime.NumGoroutine())
	//但 通道ci 还可以继续读取
	go func() {
		for v := range ci {
			log.Println(v)
		}
		c <- struct{}{}
	}()
	<-c
}

func chanDemo() {
	//无缓存通道
	c := make(chan struct{})
	go func(i chan struct{}) {
		sum := 0
		for i := 0; i < 1000; i++ {
			sum += i
		}
		log.Println(sum)
		//	写通道
		c <- struct{}{}

	}(c)
	// 返回当前程序的goroutine数目
	log.Println("NumGoroutine=", runtime.NumGoroutine())
	//	读取通道，通过通道进行同步等待

	log.Println("从通道中读取")
	<-c
}

func gofun() {
	go func() {
		sum := 0
		for i := 0; i < 1000; i++ {
			sum += i
		}
		log.Println("sum=", sum)
	}()
	//可以返回当前程序中的goroutine数目
	log.Println("NumGoroutine=", runtime.NumGoroutine())
	time.Sleep(5 * time.Second)
}

/*
goroutine如下特性
- go的执行是非阻塞的，不会等待
- go后面的函数返回值会被忽略
- 调度器不能保证多个goroutine的执行次序
- 没有父子roroutine的概念，所有的 goroutine是平等地被调度和执行的
- go程序在执行时会单独为main函数创建一个goroutine，遇到其他go关键字时在
		再去创建其他的goroutine
- GO没有暴露 goroutine id给用户，所以不能再goroutine里面显示地操作另外一个goroutine。

*/
